﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Diagnostics;

namespace System.Windows.Media.DirectShow
{
    public class BufferedOutputStream : MemoryStream
    {

        private long startOffset = -1;

        public BufferedOutputStream(IMemAllocator allocator)
        {
            this.Allocator = allocator;
        }

        public IMemAllocator Allocator
        {
            get;
            private set;
        }

        public void Reset()
        {
            this.SetLength(0);
            this.startOffset = -1;
        }

        public void AppendSample(IMediaSample sample)
        {
            AppendSample(sample, 0);
        }

        public void AppendStream(Stream stream, long offset, int length)
        {
            if (startOffset < 0)
                startOffset = 0;

            this.Seek(0, SeekOrigin.End);
            stream.Seek(offset, SeekOrigin.Begin);
            stream.WriteToStream(this, length, 0x1000);
        }

        public void AppendSample(IMediaSample sample, int offset)
        {
            long p = this.Position;
            base.Seek(0, SeekOrigin.End);
            this.Write(sample.Data, 0, (int)sample.Length);
            this.Position = p;

            if (startOffset < 0)
                startOffset = sample.StartMediaTime;

            this.Write(sample.Data, offset, (int)sample.Length - offset);
        }

        public bool HasEnoughtData
        {
            get { return this.Length >= this.Allocator.Properties.BufferSize; }
        }

        public IMediaSample GetSample(TimeSpan startTime, TimeSpan endTime)
        {
            IMediaSample sample = this.Allocator.GetBuffer(startTime, endTime);
            // Allocator not initialized
            if (sample == null) return null;

            this.Position = 0;
            sample.Length = this.Read(sample.Data, 0, (int)Math.Min(this.Allocator.Properties.BufferSize, this.Length));
            sample.StartMediaTime = startOffset;
            sample.EndMediaTime = startOffset + sample.Length;
            startOffset += sample.Length;

            byte[] buffer = this.GetBuffer();
            long diff = (this.Length - sample.Length);

            // Traslate buffer to the begin
            Buffer.BlockCopy(buffer, (int)sample.Length, buffer, 0, (int)diff);
            this.SetLength(diff);

            return sample;
        }

    }
}
